package com.e2j.utils;

/**
 * CRC32计算 (兼容Java/TypeScript/Python)
 * @author 杨永良
 * @date 22年08月09日 20:11
 *
 *
String testCode = "This is a Test!!";
int crc = CompatibleCRC32.getCrcByBytes(testCode.getBytes());
System.out.println("crc: " + crc);
System.out.println(Integer.toHexString(crc));

testCode ="这是个测试Hash的例子";
crc = CompatibleCRC32.getCrcByBytes(testCode.getBytes());
System.out.println("crc: " + crc);
testCode ="This is a 例子!!";
crc = CompatibleCRC32.getCrcByBytes(testCode.getBytes());
System.out.println("crc: " + crc);
String scrc = CompatibleCRC32.get32BitHex(testCode);
System.out.println(scrc);
**/
public class CompatibleCRC32 {
    /**
     * CRC32 = X32 + X26 + X23 + X22 + X16 + X12 + X11 + X10
     *  + X8 + X7 + X5 + X4 + X2 + X1 + X0
     */
    private static final int CN = 0x04C11DB7;
    private static final char[] HEX_MAP = new char[]{'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
    private static int[] PTI_TABLE = null; //new int[256];

    private static void buildTable() {
        if(PTI_TABLE!=null){
            return;
        }
        PTI_TABLE = new int[256];
        int nData = 0;
        int nAccum = 0;
        for (int i = 0; i < 256; i++) {
            nData = i << 24;
            nAccum = 0;
            for (int j = 0; j < 8; j++) {
                if (0 != ((nData ^ nAccum) & 0x80000000)) {
                    nAccum = (nAccum << 1) ^ CompatibleCRC32.CN;
                } else {
                    nAccum <<= 1;
                }
                nData <<= 1;
            }
            PTI_TABLE[i] = nAccum;
        }
    }

    public static int getCrcByBytes(byte[] datas) {
        buildTable();
        int crc32 = 0xFFFFFFFF;
        if (null == datas || datas.length < 1) {
            return crc32;
        }
        for (byte data : datas) {
            crc32 = (crc32 << 8) ^ PTI_TABLE[(crc32 >>> 24) ^ (data & 0xFF)];
        }
        return crc32;
    }

    public static int get32BitDec(String text){
        return getCrcByBytes(text.getBytes());
    }

    public static String get32BitHex(String text){
        int dec = get32BitDec(text);
        StringBuilder sb = new StringBuilder();
        sb.append(HEX_MAP[(dec>>>28) & 0xF]);
        sb.append(HEX_MAP[(dec>>>24) & 0xF]);
        sb.append(HEX_MAP[(dec>>>20) & 0xF]);
        sb.append(HEX_MAP[(dec>>>16) & 0xF]);
        sb.append(HEX_MAP[(dec>>>12) & 0xF]);
        sb.append(HEX_MAP[(dec>>>8) & 0xF]);
        sb.append(HEX_MAP[(dec>>>4) & 0xF]);
        sb.append(HEX_MAP[dec & 0xF]);
        return sb.toString();
    }


}